kaiax/vrank: report candidate failures against the proposer's own pri… - #992
Merged
ian0371 merged 5 commits intoAug 5, 2026
Merged
Conversation
ian0371
reviewed
Jul 22, 2026
Contributor
Author
|
@ian0371 Previously a candidate broadcast |
ian0371
reviewed
Jul 27, 2026
hyunsooda
force-pushed
the
fix/vrank-cfs-solicitor-self-report
branch
from
July 29, 2026 08:53
9e36cb1 to
60490dc
Compare
ian0371
previously approved these changes
Jul 30, 2026
…or block
A proposer now writes the candidate-failure report (cfReport) for its own
most recent prior proposal in the same epoch, instead of for the immediately
previous block. header.VRank carries the target block number, and VerifyHeader
requires proposer(target) == proposer(block). This makes the report's writer
the same validator that solicited the candidates for the target block, so a
withheld or fabricated failure is attributed to that validator's own column
and absorbed by the top-F byzantine filter.
Changes:
- types: non-epoch header.VRank payload is now CfReport{TargetBlock, Failed}
- consensus: PrepareHeader reports the proposer's own prior proposal;
VerifyHeader binds target to the same proposer and requires it be prior and
same-epoch
- handler: track own proposals and retain their collector views until reported
- collector: RemoveOldViews keeps protected (own-proposal) views past the window
- scoring: aggregation reads the target block and skips cross-epoch reports
The non-epoch header.VRank encoding changes (consensus-affecting); this must
land before the permissionless fork activates. It is safe now because
PermissionlessCompatibleBlock is nil on Mainnet and Kairos, so no committed
block carries the previous format.
Confidence: high
Scope-risk: moderate
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The non-epoch VRank cfReport carried a target block (the proposer's own most recent prior proposal) alongside the failed candidate list. Scoring attributes every failure to the reporting block's own proposer, so the target block changed neither scoring nor the property that keeps a withheld or fabricated failure in the reporting proposer's own byzantine-filterable column. Remove it: the report becomes the failed address list, VerifyHeader drops the prior/same-epoch/proposer-match checks and their errors, and the cross-epoch guard in the CP-matrix aggregation (dead once the target is gone) is removed too. Confidence: high Scope-risk: narrow Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The block's proposer is the only node that reports on a view — it evaluates the candidate replies to its own proposal and records the result in its next proposal. So a candidate now replies to that proposer alone instead of broadcasting VRankCandidate to the whole committee, and only the proposer records the preprepared time and collects the replies. HandleVRankCandidate now accepts a reply only for a view this node proposed (collector.HasPreprepared), which drops forged or misdirected messages before signature recovery and bounds collector memory to the node's own pending proposals. This removes the committee-wide collection path: the isCommitteeMember gate, the prepreparedView field, and the prepreparedView-based staleness/window guard (ErrPrepreparedViewNotSet, ErrTooFar) are no longer needed. Confidence: high Scope-risk: moderate
A non-epoch cfReport is about an earlier block of the same epoch, but VerifyHeader resolves candidate membership at the reporting block's N-1. That holds because CandTesting changes only at epoch transitions, and nothing pinned it: the other subtests wire GetCandTesting to answer at any height, so the lookup height was free to drift. Confidence: high Scope-risk: narrow Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The collector pruned views on a fixed 10-block window, which fit the old committee-wide collection but not a proposer reporting on its own prior proposal tens of blocks back. That gap was bridged by ownProposals: a second map of the sequences this node proposed, passed in as a protected set the window had to skip. The window was the wrong rule, and the protected set existed only to survive it. Prune by report progress instead. PruneReported(upto) drops every view below a sequence, called with the block just reported (its own rounds stay, so a round change or a failed commit re-reports it) and with the epoch start on each proposal, which is the only drain for a node that never has a block to report. selectReportTarget reads the pending sequences straight from the collector via PendingEvaluations, so ownProposals, its mutex, and its three helpers are gone. Confidence: high Scope-risk: narrow Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
hyunsooda
force-pushed
the
fix/vrank-cfs-solicitor-self-report
branch
from
August 4, 2026 00:44
60490dc to
cbee344
Compare
yoomee1313
approved these changes
Aug 4, 2026
2dvorak
reviewed
Aug 5, 2026
2dvorak
left a comment
Contributor
There was a problem hiding this comment.
Shouldn't we update vrank/README.md accordingly?
ian0371
approved these changes
Aug 5, 2026
Collaborator
|
Let's update |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed changes
The candidate-failure report (
cfReport) for block N was written by the proposer of block N+1, so failures were attributed to that writer rather than to block N's own proposer that requested the responses. A proposer that withholds itsVRankPrepreparethen has the induced failures charged to honest writers, spread across proposers, surviving the top-F byzantine filter.Now each proposer reports on its own most recent prior proposal (same epoch). A candidate failure is scored against the reporting block's own proposer, so a withheld or fabricated failure lands in that proposer's own byzantine-filterable column and is filtered — the report carries only the failed candidate list.
Since only that proposer uses the collected responses, a candidate now sends its
VRankCandidateto the proposer that sent theVRankPreprepareinstead of broadcasting to the whole committee, and only the proposer records and collects the replies.types: non-epochheader.VRankis the failed candidate listconsensus: report own prior proposal; validate the list againstCandTestinghandler/collector: candidates reply to the proposer; only the proposer collects, retaining its own-proposal views until reportedscoring: attribute failures to the reporting block's proposerTypes of changes
Checklist
I have read the CLA Document and I hereby sign the CLAin first time contribute after having read CLA$ make test)Related issues
Further comments